﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace PacketTester
{
    class TCP
    {

        public UInt16 SourcePort;
        public UInt16 DestinationPort;
        public UInt32 SequenceNumber;
        public UInt32 AckNumber;
        public byte DataOffsetAndReserved;
        public byte Flags; //CWR, ECE, URG, ACK, PSH, RST, SYN, FIN.
        public UInt16 WindowSize;
        public UInt16 Checksum;
        public UInt16 UrgentPointer;
        public int MessageSize;

        // there will be no options, nor necessary padding.

        public byte[] Message = new byte[128];

        public TCP()
        {
        }


        public TCP(byte[] data, int size)
        {
            foreach (byte b in data)
            {
                Console.Write(b);
                Console.Write(" | ");
            }
            Console.WriteLine("");

            SourcePort = BitConverter.ToUInt16(data, 20);//data[20];
            DestinationPort = BitConverter.ToUInt16(data, 22);// data[22];
            SequenceNumber = BitConverter.ToUInt32(data, 24);
            AckNumber = BitConverter.ToUInt32(data, 28);
            DataOffsetAndReserved = data[32];
            Flags = data[33];
            WindowSize = BitConverter.ToUInt16(data, 34);
            Checksum = BitConverter.ToUInt16(data, 36);
            UrgentPointer = BitConverter.ToUInt16(data, 38);

            MessageSize = size - 40;
            Buffer.BlockCopy(data, 40, Message, 0, MessageSize);
        }

        public byte[] getBytes()
        {
            byte[] data = new byte[MessageSize + 20];
            Buffer.BlockCopy(BitConverter.GetBytes(SourcePort), 0, data, 0, 2);
            Buffer.BlockCopy(BitConverter.GetBytes(DestinationPort), 0, data, 2, 2);
            Buffer.BlockCopy(BitConverter.GetBytes(SequenceNumber), 0, data, 4, 4);
            Buffer.BlockCopy(BitConverter.GetBytes(AckNumber), 0, data, 8, 4);
            Buffer.BlockCopy(BitConverter.GetBytes(DataOffsetAndReserved), 0, data, 12, 1);
            Buffer.BlockCopy(BitConverter.GetBytes(Flags), 0, data, 13, 1);
            Buffer.BlockCopy(BitConverter.GetBytes(WindowSize), 0, data, 14, 2);
            Buffer.BlockCopy(BitConverter.GetBytes(Checksum), 0, data, 16, 2);
            Buffer.BlockCopy(BitConverter.GetBytes(UrgentPointer), 0, data, 18, 2);
            Buffer.BlockCopy(Message, 0, data, 20, MessageSize);
            return data;
        }

        public UInt16 getChecksum()
        {
            UInt32 chcksm = 0;
            byte[] data = getBytes();
            int packetsize = MessageSize + 20;
            int index = 0;

            while (index < packetsize)
            {
                chcksm += Convert.ToUInt32(BitConverter.ToUInt16(data, index));
                index += 2;
            }
            chcksm = (chcksm >> 16) + (chcksm & 0xffff);
            chcksm += (chcksm >> 16);
            return (UInt16)(~chcksm);
        }

    }
}
